package com.zqxx.examine.model.exam;


import com.zqxx.examine.common.utils.Roulette;
import com.zqxx.examine.model.question.QuestionStruts;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Paper
{
  public static Logger log = LoggerFactory.getLogger(Paper.class);
  private HashMap<Integer, QuestionStruts> paperQuestionMap = new HashMap();
  private float fitness;
  private double exposure;
  private float difficulty;
  private float eDifficulty = 0.2F;
  private HashMap<Integer, Integer> questionTypeNum;
  private HashMap<Integer, Float> questionTypePoint;
  private HashMap<Integer, String> knowledgeMap;
  private HashMap<Integer, String> typeMap;
  private HashMap<Integer, Float> knowledgePointRate;
  private int questionNum = 0;
  private HashMap<Integer, HashMap<Integer, List<QuestionStruts>>> questionMap;
  
  public HashMap<Integer, QuestionStruts> getPaperQuestionMap()
  {
    return this.paperQuestionMap;
  }
  
  public Paper(HashMap<Integer, HashMap<Integer, List<QuestionStruts>>> questionMap, HashMap<Integer, Integer> questionTypeNum, HashMap<Integer, Float> questionTypePoint, HashMap<Integer, Float> knowledgePointRate, HashMap<Integer, String> knowledgeMap, HashMap<Integer, String> typeMap)
  {
    this.questionMap = questionMap;
    this.questionTypeNum = questionTypeNum;
    this.questionTypePoint = questionTypePoint;
    this.knowledgePointRate = knowledgePointRate;
    this.knowledgeMap = knowledgeMap;
    this.typeMap = typeMap;
  }
  
  public void createPaper()
    throws Exception
  {
    HashMap<Integer, Integer> questionTypeNumCheck = new HashMap();
    Iterator<Integer> iterator1 = this.questionMap.keySet().iterator();
    while (iterator1.hasNext())
    {
      int key = ((Integer)iterator1.next()).intValue();
      
      Iterator<Integer> iterator2 = ((HashMap)this.questionMap.get(Integer.valueOf(key))).keySet().iterator();
      while (iterator2.hasNext())
      {
        int typeNum = ((Integer)iterator2.next()).intValue();
        if (questionTypeNumCheck.containsKey(Integer.valueOf(typeNum))) {
          questionTypeNumCheck.put(Integer.valueOf(typeNum), 
            Integer.valueOf(((Integer)questionTypeNumCheck.get(Integer.valueOf(typeNum))).intValue() + 
            ((List)((HashMap)this.questionMap.get(Integer.valueOf(key))).get(Integer.valueOf(typeNum))).size()));
        } else {
          questionTypeNumCheck.put(Integer.valueOf(typeNum), 
            Integer.valueOf(((List)((HashMap)this.questionMap.get(Integer.valueOf(key))).get(Integer.valueOf(typeNum))).size()));
        }
      }
    }
    Iterator<Integer> iterator3 = this.questionTypeNum.keySet().iterator();
    while (iterator3.hasNext())
    {
      int key = ((Integer)iterator3.next()).intValue();
      if (!questionTypeNumCheck.containsKey(Integer.valueOf(key))) {
        throw new Exception("试题清单中无试题类型" + (String)this.typeMap.get(Integer.valueOf(key)));
      }
      if (((Integer)this.questionTypeNum.get(Integer.valueOf(key))).intValue() > ((Integer)questionTypeNumCheck.get(Integer.valueOf(key))).intValue()) {
        throw new Exception("试题库中试题类型：" + (String)this.typeMap.get(Integer.valueOf(key)) + "数量不足");
      }
    }
    this.paperQuestionMap = new HashMap();
    

    List<Integer> resultList = new ArrayList();
    
    HashMap<Integer, Float> hm = new HashMap();
    
    float sum = 0.0F;
    if (this.knowledgePointRate != null)
    {
      Iterator<Integer> itrate = this.knowledgePointRate.keySet().iterator();
      while (itrate.hasNext()) {
        sum += ((Float)this.knowledgePointRate.get(itrate.next())).floatValue();
      }
    }
    if ((this.knowledgePointRate == null) || (sum != 1.0F))
    {
      Iterator<Integer> it = this.questionMap.keySet().iterator();
      int count = 0;
      while (it.hasNext())
      {
        int key = ((Integer)it.next()).intValue();
        resultList.add(Integer.valueOf(key));
        hm.put(Integer.valueOf(count), Float.valueOf(0.0F));
        count++;
      }
      it = this.questionMap.keySet().iterator();
      
      float avg = Math.round(1.0F / count * 1000.0F) / 1000.0F;
      
      float dt = Math.round((1.0F - avg * (count - 1)) * 1000.0F) / 1000.0F;
      
      log.info("dt = " + dt);
      log.info("avg = " + avg);
      for (int i = 0; i < count; i++)
      {
        if (i == count - 1) {
          hm.put(Integer.valueOf(i), Float.valueOf(dt));
        } else {
          hm.put(Integer.valueOf(i), Float.valueOf(avg));
        }
        log.info("知识点" + i + "的选择概率:" + hm.get(Integer.valueOf(i)));
      }
    }
    else
    {
      Iterator<Integer> itrate1 = this.knowledgePointRate.keySet().iterator();
      int count = 0;
      while (itrate1.hasNext())
      {
        int key = ((Integer)itrate1.next()).intValue();
        resultList.add(Integer.valueOf(key));
        hm.put(Integer.valueOf(count), this.knowledgePointRate.get(Integer.valueOf(key)));
        count++;
      }
    }
    Roulette<Integer> r = new Roulette(resultList, hm);
    

    List<Integer> resultList1 = new ArrayList();
    Iterator<Integer> it1 = this.questionTypeNum.keySet().iterator();
    HashMap<Integer, Float> hm1 = new HashMap();
    
    int count1 = 0;
    while (it1.hasNext())
    {
      int key = ((Integer)it1.next()).intValue();
      resultList1.add(Integer.valueOf(key));
      
      count1++;
      
      this.questionNum += ((Integer)this.questionTypeNum.get(Integer.valueOf(key))).intValue();
    }
    log.info("题型数量=" + count1);
    
    it1 = this.questionMap.keySet().iterator();
    

    float avg1 = Math.round(1.0F / count1 * 1000.0F) / 1000.0F;
    

    float dt1 = Math.round((1.0F - avg1 * (count1 - 1)) * 1000.0F) / 1000.0F;
    for (int i = 0; i < count1; i++)
    {
      if (i == count1 - 1) {
        hm1.put(Integer.valueOf(i), Float.valueOf(dt1));
      } else {
        hm1.put(Integer.valueOf(i), Float.valueOf(avg1));
      }
      log.info("题型" + i + "的选择概率:" + hm1.get(Integer.valueOf(i)));
    }
    Roulette<Integer> r1 = new Roulette(resultList1, hm1);
    while (this.questionNum > this.paperQuestionMap.size())
    {
      int pointId = -1;
      int typeId = -1;
      try
      {
        pointId = ((Integer)r.getResult()).intValue();
        typeId = ((Integer)r1.getResult()).intValue();
        List<QuestionStruts> qs = (List)((HashMap)this.questionMap.get(Integer.valueOf(pointId))).get(Integer.valueOf(typeId));
        if (qs == null)
        {
          log.info("pointId=" + pointId + "typeId=" + typeId);
        }
        else
        {
          Random random = new Random();
          int typeNum = ((Integer)this.questionTypeNum.get(Integer.valueOf(typeId))).intValue();
          if (typeNum > 0)
          {
            QuestionStruts q = (QuestionStruts)qs.get(random.nextInt(qs.size()));
            if (this.paperQuestionMap.containsKey(Integer.valueOf(q.getQuestionId()))) {
              continue;
            }
            if ((this.questionTypePoint != null) && 
              (this.questionTypePoint.containsKey(Integer.valueOf(typeId)))) {
              q.setPoint(((Float)this.questionTypePoint.get(Integer.valueOf(typeId))).floatValue());
            }
            this.paperQuestionMap.put(Integer.valueOf(q.getQuestionId()), q);
            typeNum--;
            this.questionTypeNum.put(Integer.valueOf(typeId), Integer.valueOf(typeNum));
          }
        }
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }
    }
  }
  
  private void setFitness()
  {
    float difficultyMinus = Math.abs(this.difficulty - this.eDifficulty);
    log.info("eDifficulty=" + this.eDifficulty);
    
    this.fitness = ((float)(1.0F / difficultyMinus * Math.sqrt(this.exposure)));
  }
  
  public float getFitness()
  {
    return this.fitness;
  }
  
  public void initPaper()
  {
    float pointLose = 0.0F;
    float pointSum = 0.0F;
    double exposureSum = 0.0D;
    Iterator<Integer> it = this.paperQuestionMap.keySet().iterator();
    while (it.hasNext())
    {
      int key = ((Integer)it.next()).intValue();
      QuestionStruts q = (QuestionStruts)this.paperQuestionMap.get(Integer.valueOf(key));
      
      pointLose = (float)(pointLose + q.getWrongTimes() / q.getExposeTimes() * q.getPoint());
      pointSum += q.getPoint();
      exposureSum += q.getExposeTimes();
    }
    this.difficulty = (pointLose / pointSum);
    log.info("difficulty=" + this.difficulty);
    this.exposure = exposureSum;
    setFitness();
  }
}